package com.toobigtofail.enitities
{
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Fixture;
	
	import com.toobigtofail.Game;
	import com.toobigtofail.shapes.IShape;
	import com.toobigtofail.utility.Util;
	
	import fabulaexmachina.box2fp.Box2DEntity;
	import fabulaexmachina.box2fp.Box2DShapeBuilder;
	import fabulaexmachina.box2fp.Box2DWorld;
	import fabulaexmachina.box2fp.graphics.SuperGraphiclist;
	
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import net.flashpunk.FP;
	import net.flashpunk.Sfx;
	import net.flashpunk.Tween;
	import net.flashpunk.graphics.Image;
	import net.flashpunk.graphics.Spritemap;
	import net.flashpunk.tweens.misc.NumTween;
	import net.flashpunk.utils.Draw;
	import net.flashpunk.utils.Ease;
	import net.flashpunk.utils.Input;
	import net.flashpunk.utils.Key;
	
	import punk.bloom.BloomWrapper;
	import punk.blur.BlurCanvas;
	import punk.blur.BlurWrapper;
	import punk.blur.BlurredGraphic;
	
	public class Player extends Box2DEntity
	{
		[Embed(source="/assets/gfx/spritestrip.png")] private static const PLAYER_IMG:Class;
		
		
		[Embed(source="/assets/sfx/powerReady.mp3")] private const POWER_RDY_SFX:Class;
		[Embed(source="/assets/sfx/sonicBoom.mp3")]  private const SONIC_BOOM_SFX:Class;
		
		public static const TYPE:String = "player";
		public static const POS_OFFSET:Number = 80;		
		
		public var img:Spritemap = new Spritemap(PLAYER_IMG, 32, 32);
		
		private static const EXPLOSION_RADIUS:uint = 400;
		
		private static const MOVE_FORCE:Number = 50.0;
		private static const MOVE_LEFT_VEC:b2Vec2 = new b2Vec2(-MOVE_FORCE, 0);
		private static const MOVE_RIGHT_VEC:b2Vec2 = new b2Vec2(MOVE_FORCE, 0);
		
		public static const MAX_POWER:Number = 100;
		
		private var _power:Number = 0;
				
		private var _shape:IShape;
		
		private var _explosionSpriteRect:Rectangle = new Rectangle(0,0,EXPLOSION_RADIUS*2,EXPLOSION_RADIUS*2);
		private var _explosionSprite:BitmapData;
		private var _explosionTween:NumTween;
		
		//private var _bloomWrapper:BloomWrapper;
		private var _blurredGraphic:BlurredGraphic;
		private var _allowBlur:Boolean = true;
		
		//sfx
		private var _sfx:Array = new Array;
		
		public function Player(shape:IShape)
		{
			_sfx["power_rdy"]  = new Sfx(POWER_RDY_SFX);
			_sfx["sonic_boom"] = new Sfx(SONIC_BOOM_SFX);
						
			_explosionSprite = new BitmapData(_explosionSpriteRect.width, _explosionSpriteRect.height, true, 0);
			_explosionTween = new NumTween(null, Tween.PERSIST);
			addTween(_explosionTween);
			
			_shape = shape;
			super(shape.X, shape.Y, shape.Width, shape.Height,shape.b2Type);
			type = TYPE;
			gravity = new b2Vec2(0,0);
						
			img.add("flail", [1,2,3], 24, true);
			//var img:Image = Image.createRect(this.Width * (FP.world as Box2DWorld).scale, this.Height * (FP.world as Box2DWorld).scale, 0xF1FFFF);
			img.x = (this.Width * (FP.world as Box2DWorld).scale / -2)-2;
			img.y = (this.Height * (FP.world as Box2DWorld).scale / -2)-2;
			
			//_bloomWrapper = new BloomWrapper(img);
			//blur and bloom
			this.graphic = img;
		}
		
		override public function added():void {
			super.added();
		}
		
		override public function buildShapes(friction:Number, 
											 density:Number, restitution:Number,
											 group:int, category:int, collmask:int):void { 
			_shape.buildShape(body);
		}
		
		override public function update():void {
			
			// Use power
			if (isPowerReady() && Input.pressed(Key.SPACE) && !_explosionTween.active) {
				_sfx["sonic_boom"].play(0.3);
				power = power*.3;
				_explosionTween.tween(0, EXPLOSION_RADIUS, 0.2, Ease.expoIn);
				
				body.SetAngle(0);
			}
			
			// Kill enemies within explosion
			if (_explosionTween.active) {
				body.SetAngularDamping(100);
				var enemies:Array = new Array;
				FP.world.getType("enemy", enemies);
				FP.world.getType("shit", enemies);
				
				var xy:b2Vec2 = new b2Vec2(x, y);
				for each (var e:Box2DEntity in enemies) {
					var p:b2Vec2 = new b2Vec2(e.x,e.y);
					p.Subtract(xy);
					p.Abs();
					if (Util.isWithin(p, _explosionTween.value)) {
						e.remove();
					}
				}
			}
			else {
				
				body.SetAngularDamping(0);
			}
			
			var powerNotReady:Boolean = _power < MAX_POWER;
			_power += FP.elapsed * (world as Game).speed*4;
			if (_power >= MAX_POWER) {
				if (powerNotReady) {
					if (_allowBlur) _blurredGraphic.isBlurring = true;
					(_sfx["power_rdy"] as Sfx).play(0.3);
				}
				_power = MAX_POWER;	
			}
			else if (powerNotReady && _blurredGraphic.isBlurring) {
				_blurredGraphic.isBlurring = false;
			}
			
			var hh:Number = (FP.screen.height/2  - Player.POS_OFFSET) / (FP.world as Box2DWorld).scale;
			var wc:b2Vec2 = body.GetWorldCenter();
			var lv:b2Vec2 = body.GetLinearVelocity();
			
			//trace("hh: " + hh + ", wc: " + wc + ", lv: " + lv);
			// If the center of the player is not in the middle of the screen (hh),
			// then adjust the velocity, so the player stays centered
			if (Math.round(wc.y) != Math.round(hh)) {
				var yv:Number = 0;
				
				// If the player is above the center then something hit it to make him
				// move upward. In this case the player should slow down.
				// Since the player isn't really moving, but the world is, we slow down the world.
				if (wc.y < hh) {
					yv = (hh - wc.y);
					(world as Game).speed = (world as Game).speed*0.75;
					_power -= MAX_POWER*0.25;
					if (_power < 0) _power = 0;
				}
				
				// Keep any x velocity, but set the y velocity as appropriate to keep the player in the center of the screen
				body.SetLinearVelocity(new b2Vec2(lv.x, yv));
			}
			
			// move left and right
			if (Input.check(Key.LEFT)) {
				if (lv.x > 0) {
					body.SetLinearVelocity(new b2Vec2(lv.x/2, lv.y));
				}
				body.ApplyForce(MOVE_LEFT_VEC, body.GetWorldCenter());
			}
			if (Input.check(Key.RIGHT)) {
				if (lv.x < 0) {
					body.SetLinearVelocity(new b2Vec2(lv.x/2, lv.y));
				}
				body.ApplyForce(MOVE_RIGHT_VEC, body.GetWorldCenter());
			}
			animate();
			super.update();
		}
		
		override public function render():void {
			super.render();
			// Draw the explosion!
			if (isUsingPower()) {
				Draw.setTarget(_explosionSprite);
				_explosionSprite.fillRect(_explosionSpriteRect, 0);
				
				for (var i:Number = 1; i > 0; i -= .1) {
					Draw.circlePlus(EXPLOSION_RADIUS, EXPLOSION_RADIUS, _explosionTween.value*Math.log(i), 0xFFFFFF, i, false, 3);
				}
				
				var wc:b2Vec2 = body.GetWorldCenter().Copy();
				wc.Multiply((FP.world as Box2DWorld).scale);
				wc.Subtract(new b2Vec2(_explosionSpriteRect.width/2, _explosionSpriteRect.height/2));
				FP.buffer.copyPixels(_explosionSprite, _explosionSpriteRect, new Point(wc.x, wc.y));
			}
		}
		
		public function blur(blurCan:BlurCanvas):void
		{
			if(!(graphic is BlurredGraphic))
				_blurredGraphic = new BlurredGraphic(graphic, blurCan);
				var blurSGL:SuperGraphiclist = new SuperGraphiclist(_blurredGraphic);
				graphic = blurSGL;
			
		}
		public function animate():void
		{
			img.play("flail");
		}
		
		public function isPowerReady():Boolean {
			return (power / MAX_POWER) == 1;
		}
		
		public function isUsingPower():Boolean {
			return _explosionTween.active;
		}
		
		//public function get bloomWrapper():BloomWrapper { return _bloomWrapper; }
		public function set allowBlur(b:Boolean):void { 
			_allowBlur = b;
			if (isPowerReady() && b) {
				_blurredGraphic.isBlurring = true;
			}
			else if (!b) {
				_blurredGraphic.isBlurring = false;
			}
		}
		public function get allowBlur():Boolean { return _allowBlur; }
		
		public function get power():Number { return _power; }
		public function set power(p:Number):void { p > MAX_POWER ? MAX_POWER : _power = p; }
	}
}